﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Omu.Awesome.Core;

using DR.Repository.Abstract;
using DR.DBDomainModel;
using DR.WebUI.Code;
using DR.WebUI.Models.Enums;
using DR.WebUI.Models.Developer;
using DR.WebUI.Models.Account;


namespace DR.WebUI.Controllers
{
    [Authorize(Roles = "developer")]
    public class DeveloperController : Controller
    {
        public int PageSize { get; set; }
        private readonly IReportRepository reportRepository;        
        private readonly IReportingPeriodRepository reportingPeriodRepository;
        private readonly IProjectRepository projectRepository;
        private readonly IDeveloperRepository developerRepository;
        private readonly IDeveloperProjectRepository developerProjectRepository;

        public DeveloperController(
            IProjectRepository projectRepository, 
            IReportRepository taskRepository, 
            IDeveloperProjectRepository developerProjectRepository, 
            IDeveloperRepository developerRepository, 
            IReportingPeriodRepository reportingPeriodRepository)
        {            
            this.reportRepository = taskRepository;
            this.projectRepository = projectRepository;
            this.developerProjectRepository = developerProjectRepository;
            this.developerRepository = developerRepository;
            this.reportingPeriodRepository = reportingPeriodRepository;
            PageSize = 15;
        }

        public ActionResult Menu()
        {
            return View();
        }

        [HttpGet]
        [Authorize(Roles="developer")]
        public ViewResult MyReports(ReportFilter filter, CurrentUser currentUser, int page = 1)
        {
            Developer developer = developerRepository.SelectDeveloperByUserID(currentUser.UserID);

            IList<ReportingPeriod> reportingPeriods = reportingPeriodRepository.SelectAll();
            ReportingPeriod currentReportingPeriod = GetCurrentReportingPeriod(filter.ReportingPeriodID, reportingPeriods);

            if (!filter.ReportingPeriodID.HasValue)
            {
                filter.ReportingPeriodID = (currentReportingPeriod != null ? currentReportingPeriod.ReportingPeriogID : (int?)null);
            }

            bool isClosedCurrentReportingPeriod = (currentReportingPeriod != null ? currentReportingPeriod.IsFinished : false);
            //TODO: Написать вибірку по поточному девелоперу
            IList<ReportModel> reportsOverviewModels = reportRepository
                .SelectByFilter(filter.ReportingPeriodID, filter.ProjectID, developer.DeveloperID, filter.SelectedReportStatuses)                        
                .Select(r => new ReportModel
                                 {
                                     ReportID = r.ReportID,
                                     Project = r.DeveloperProject.Project.Name,                                     
                                     DateReporting = r.DateReporting,
                                     Hours = r.Hours,
                                     State = (ReportStatus) r.State,
                                     DateCreate = r.DateCreate,
                                     DateModified = r.DateModified,
                                     Title = r.Title,
                                     CanDeleteByDeveloper = (r.State == (int)ReportStatus.Pending 
                                        && !isClosedCurrentReportingPeriod 
                                        && r.DeveloperProject.DeveloperID == developer.DeveloperID),
                                     CanEditByDeveloper = (r.State == (int)ReportStatus.Pending
                                        && !isClosedCurrentReportingPeriod
                                        && r.DeveloperProject.DeveloperID == developer.DeveloperID)
                                })
                .ToList();
                
            IList<SelectListItem> reportingPeriodListItems = reportingPeriods
                .OrderBy(r => r.DateStart)
                .Select(r => new SelectListItem
                    {
                        Value = r.ReportingPeriogID.ToString(),
                        Text = r.Caption,
                        Selected = (filter.ReportingPeriodID.HasValue ? filter.ReportingPeriodID == r.ReportingPeriogID : false) 
                    })
                .ToList();
            
            ViewData["ReportFilter"] = filter;

            ViewData["ReportingPeriods"] = reportingPeriodListItems;

            IList<Project> projects = projectRepository.SelectAccessibleForDeveloper(developer.DeveloperID);
            IList<SelectListItem> projectsItems = projects
                .OrderBy(r => r.Name)
                .Select(r => new SelectListItem 
                    { 
                        Value = r.ProjectID.ToString(), 
                        Text = r.Name, 
                        Selected = (filter.ProjectID.HasValue ? filter.ProjectID == r.ProjectID : false) 
                    })
                .ToList();

            if (projectsItems.Count > 0)
            {
                projectsItems.Insert(0, new SelectListItem { Value = "", Text = "All" });
            }

            ViewData["Projects"] = projectsItems;
            ViewData["ReportStatuses"] = MiscHelpers.GetAllFilterReportStatuses();

            ViewData["ShownDeleteButton"] = (reportsOverviewModels.Count(r => r.CanDeleteByDeveloper) > 0);
            ViewData["ShownEditButton"] = (reportsOverviewModels.Count(r => r.CanEditByDeveloper) > 0);

            return View(new Pageable<ReportModel>
            {      
                PageIndex = page,
                PageCount = MiscHelpers.GetPageCount(PageSize, reportsOverviewModels.Count),
                Page = reportsOverviewModels.Skip((page - 1) * PageSize).Take(PageSize)
            });   
        }

        private ReportingPeriod GetCurrentReportingPeriod(int? filterReportingPeriodId, IEnumerable<ReportingPeriod> reportingPeriods)
        {
            if (!filterReportingPeriodId.HasValue)
            {
                return reportingPeriods
                    .Where(r => !r.IsFinished)
                    .OrderBy(r => r.DateStart)
                    .LastOrDefault();
            }

            return reportingPeriods.LastOrDefault(r => r.ReportingPeriogID == filterReportingPeriodId.Value);

            //return reportingPeriods
            //    .Where(r => !r.IsFinished)
            //    .OrderBy(r => r.DateStart)
            //    .Last();
        }

        [HttpPost]
        public ActionResult SetupReportFilter(ReportFilter filter, string filterButton, int reportingPeriodID, int? projectID, int[] statuses)
        {
            if (filterButton == "Apply")
            {
                filter.ReportingPeriodID = reportingPeriodID;
                filter.ProjectID = projectID;
                filter.SelectedReportStatuses.Clear();
                if (statuses != null)
                {
                    filter.SelectedReportStatuses.UnionWith(statuses);
                }
            }
            else
            {
                // set default reporting period
                filter.ReportingPeriodID = null;
                filter.ProjectID = null;
                filter.SelectedReportStatuses.Clear();
                filter.SelectedReportStatuses.UnionWith(Enum.GetValues(typeof(ReportStatus)).Cast<int>());
            }
            return RedirectToAction("MyReports");
        }

        [HttpPost]
        public JsonResult ApproveReport(int id, decimal hours)
        {
            reportRepository.ChangeHours(id, hours);

            return Json(new { result = "ok" });
        }

        [HttpPost]
        public JsonResult DeleteReport(int reportId, CurrentUser currentUser)
        {
            Developer developer = developerRepository.SelectDeveloperByUserID(currentUser.UserID);
            var report = reportRepository.SelectByID(reportId);
            ReportingPeriod reportingPeriod = reportingPeriodRepository.SelectByID(report.ReportingPeriodID);


            bool canBeDeleted =
                !reportingPeriod.IsFinished &&
                report.State == (int) ReportStatus.Pending &&
                report.DeveloperProject.DeveloperID == developer.DeveloperID;
            if (canBeDeleted)
            {
                reportRepository.Delete(reportId);
            }          
            return Json(new { result = canBeDeleted });
        }

        [HttpGet]
        public ActionResult ViewReportDetails(int id, CurrentUser currentUser)
        {
            var developer = developerRepository.SelectDeveloperByUserID(currentUser.UserID);
            var report = reportRepository.SelectAll().FirstOrDefault(r => r.ReportID == id);
            var reportingPeriod = reportingPeriodRepository.SelectAll().FirstOrDefault(r => r.ReportingPeriogID == report.ReportingPeriodID);
            bool isClosedCurrentReportingPeriod = (reportingPeriod != null ? reportingPeriod.IsFinished : false);
           
            var reportModel = new DeveloperReportDetailModel()
            {
                ReportID = report.ReportID,
                Title = report.Title,
                Project = report.DeveloperProject.Project.Name,
                Hours = FormatHelpers.FormatHours(report.Hours),
                State = ((ReportStatus)report.State).ToString(),
                DateCreate = FormatHelpers.FormatDateTime(report.DateCreate),
                DateReporting = FormatHelpers.FormatDate(report.DateReporting),
                DateModified = FormatHelpers.FormatDateTime(report.DateModified),
                Description = report.Description,
                ReportingPeriod = reportingPeriod.Caption,
                CanDeleteByDeveloper = !isClosedCurrentReportingPeriod
                                        && report.DeveloperProject.DeveloperID == developer.DeveloperID
                                        && report.State == (int)ReportStatus.Pending,
                CanEditByDeveloper  = !isClosedCurrentReportingPeriod
                                        && report.DeveloperProject.DeveloperID == developer.DeveloperID
                                        && report.State == (int)ReportStatus.Pending
            };

            return View(reportModel );
        }

        #region Add New Report
        //TODO: Потрібний рефакторінг
        [HttpGet]
        public ActionResult AddNewReport(CurrentUser currentUser)
        {
            #region ViewData-DeveloperProjects
            Developer developer = developerRepository.SelectDeveloperByUserID(currentUser.UserID);
            IList<Project> selectAccessibleForDeveloper = projectRepository.SelectAccessibleForDeveloper(developer.DeveloperID);
            IList<SelectListItem> projectsItems = selectAccessibleForDeveloper
                .OrderBy(r => r.Name)
                .Select(r => new SelectListItem { Value = r.ProjectID.ToString(), Text = r.Name })
                .ToList();
            ViewData["ProjectsList"] = projectsItems;
            #endregion

            #region ViewData-ReportPeriodList
            IEnumerable<ReportingPeriod> reportingPeriods = reportingPeriodRepository.SelectAll().Where(n => n.IsFinished == false).OrderByDescending(n => n.ReportingPeriogID);
            IList<SelectListItem> reportingPeriodsItems = reportingPeriods
                .Select(r => new SelectListItem { Value = r.ReportingPeriogID.ToString(), Text = r.Caption})
                .ToList();         
            ViewData["ReportPeriodList"] = reportingPeriodsItems;
            #endregion

            var newReport = new NewReport{Date = DateTime.Now};

            return View(newReport);
        }

        [HttpPost]
        //TODO: Потрібний рефакторінг
        public ActionResult AddNewReport(NewReport report, CurrentUser currentUser)
        {
            IEnumerable<ReportingPeriod> reportingPeriods = reportingPeriodRepository.SelectAll().Where(n => n.IsFinished == false);
            ReportingPeriod item = reportingPeriods.SingleOrDefault(n => n.ReportingPeriogID == report.ReportingPeriodID);

            int startCompare = DateTime.Compare(item.DateStart, report.Date);
            int finishCompare = DateTime.Compare(report.Date, item.DateFinish);

            if (finishCompare > 0 || startCompare > 0)
            {
                ModelState.AddModelError("Date", "This date is not included in this period");
            }

            var developer = developerRepository.SelectDeveloperByUserID(currentUser.UserID);
            var developerProject = developerProjectRepository.SelectAll().FirstOrDefault(n => n.DeveloperID == developer.DeveloperID && n.ProjectID == report.ProjectID);

            if (ModelState.IsValid)
            {
                reportRepository.Insert(new Report
                                            {
                                                DateCreate = DateTime.Now,
                                                DateReporting = report.Date,
                                                Title = report.Title,
                                                Description = report.Description,
                                                ReportingPeriodID = report.ReportingPeriodID,
                                                Hours = report.Hours,
                                                State = (int) ReportStatus.Pending,
                                                DeveloperProjectID = developerProject.DeveloperProjectID
                                            });

                return RedirectToAction("MyReports");
            }

            #region ViewData-DeveloperProjects
            IList<Project> selectAccessibleForDeveloper = projectRepository.SelectAccessibleForDeveloper(developer.DeveloperID);
            IList<SelectListItem> projectsItems = selectAccessibleForDeveloper
                .OrderBy(r => r.Name)
                .Select(r => new SelectListItem { Value = r.ProjectID.ToString(), Text = r.Name })
                .ToList();
            ViewData["ProjectsList"] = projectsItems;
            #endregion

            #region ViewData-ReportPeriodList
            IList<SelectListItem> reportingPeriodsItems = reportingPeriods
            .Select(r => new SelectListItem { Value = r.ReportingPeriogID.ToString(), Text = r.Caption, Selected = false })
            .ToList();
            ViewData["ReportPeriodList"] = reportingPeriodsItems;
            #endregion

            return View(report);
        } 
        #endregion

        #region EditReport
        [HttpGet]
        //TODO: Потрібний рефакторінг
        public ActionResult EditReport(int reportID, CurrentUser currentUser)
        {
            var currentReport = reportRepository.SelectByID(reportID);
            var developer = developerRepository.SelectDeveloperByUserID(currentUser.UserID);

            IList<Project> developerProjects = projectRepository.SelectAccessibleForDeveloper(developer.DeveloperID);

            var editReport = new EditReport
            {
                Title = currentReport.Title,
                ProjectID = currentReport.DeveloperProject.ProjectID,
                DateCreate = currentReport.DateCreate,
                DateModified = currentReport.DateModified,
                DateReporting = currentReport.DateReporting,
                Hours = currentReport.Hours,
                Description = currentReport.Description,
                ReportID = currentReport.ReportID,
                ReportingPeriodID = currentReport.ReportingPeriodID
            };

            #region ViewData-ReportPeriodList
            IEnumerable<ReportingPeriod> reportingPeriods = reportingPeriodRepository.SelectAll().Where(n => n.IsFinished == false);
            IList<SelectListItem> reportingPeriodsItems = reportingPeriods
                .Select(r => new SelectListItem { Value = r.ReportingPeriogID.ToString(), Text = r.Caption, Selected = (r.ReportingPeriogID == editReport.ReportingPeriodID) })
                .ToList();
            ViewData["EditReportPeriodList"] = reportingPeriodsItems;
            #endregion

            #region ViewData-DeveloperProjects
            IList<SelectListItem> developerProjectsItems =
                   developerProjects.OrderBy(r => r.Name).Select(r => new SelectListItem
                   {
                       Value = r.ProjectID.ToString(),
                       Text = r.Name,
                       Selected =
                           (r.ProjectID == editReport.ProjectID)

                   })
                       .ToList();
            ViewData["DeveloperProjects"] = developerProjectsItems;
            #endregion
          

            return View(editReport);
        }

        [HttpPost]
        //TODO: Потрібний рефакторінг
        public ActionResult EditReport(EditReport editReport, CurrentUser currentUser)
        {
            Developer developer = developerRepository.SelectDeveloperByUserID(currentUser.UserID);
            var currentReport = reportRepository.SelectByID(editReport.ReportID);
            DeveloperProject developerProject = developerProjectRepository.GetDeveloperProject(developer.DeveloperID, editReport.ProjectID);

            #region ViewData-ReportPeriodList
            IEnumerable<ReportingPeriod> reportingPeriods = reportingPeriodRepository.SelectAll().Where(n => n.IsFinished == false);
            ReportingPeriod item = reportingPeriods.SingleOrDefault(n => n.ReportingPeriogID == editReport.ReportingPeriodID);
            IList<SelectListItem> reportingPeriodsItems = reportingPeriods
                .Select(r => new SelectListItem { Value = r.ReportingPeriogID.ToString(), Text = r.Caption, Selected = (r.ReportingPeriogID == currentReport.ReportingPeriodID) })
                .ToList();
            ViewData["EditReportPeriodList"] = reportingPeriodsItems;
            #endregion

            #region ViewData-DeveloperProjects
            IList<Project> developerProjects = projectRepository.SelectAccessibleForDeveloper(developer.DeveloperID);
            IList<SelectListItem> developerProjectsItems = developerProjects
               .OrderBy(r => r.Name)
               .Select(r => new SelectListItem
               {
                   Value = r.ProjectID.ToString(),
                   Text = r.Name,
                   Selected = (r.ProjectID == editReport.ProjectID)

               })
               .ToList();
            ViewData["DeveloperProjects"] = developerProjectsItems; 
            #endregion

            int startCompare = DateTime.Compare(item.DateStart, editReport.DateReporting);
            int finishCompare = DateTime.Compare(editReport.DateReporting, item.DateFinish);

            if (finishCompare > 0 || startCompare > 0)
            {
                ModelState.AddModelError("DateReporting", "This date is not included in this period");
            }

            if (ModelState.IsValid)
            {
                var report = new Report
                {
                    ReportID = currentReport.ReportID,
                    Title = editReport.Title,
                    Description = editReport.Description,
                    Hours = editReport.Hours,
                    DateCreate = currentReport.DateCreate,
                    DateReporting = editReport.DateReporting,
                    DateModified = editReport.DateModified,
                    DeveloperProjectID = developerProject.DeveloperProjectID,
                    State = currentReport.State,
                    ReportingPeriodID = editReport.ReportingPeriodID
                };

                reportRepository.Update(report);
                return RedirectToAction("MyReports");
            }

            return View(editReport);
        } 
        #endregion
    }
}
